#pragma once

#include <sys/types.h>
#include <sys/socket.h>

#include "Log.hpp"
#include "Connection.hpp"

class HandlerConnection
{
public:
    HandlerConnection(func_t func) : _func(func) {}

    void HandlerRecv(Connection *conn)
    {
        errno = 0; // 清空errno;
        LOG(DEBUG, "HanlderRecv fd : %d\n", conn->Sockfd());
        while (true)
        {
            char buffer[1024];
            int n = ::recv(conn->Sockfd(), buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                conn->AppendInbuffer(buffer);
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    conn->_excepter(conn);
                    return; // ？提前返回
                }
            }
        }
        _func(conn);
    }

    void HandlerSend(Connection *conn)
    {
        errno = 0;
        while (true)
        {
            int n = ::send(conn->Sockfd(), conn->Outbuffer().c_str(), conn->Outbuffer().size(), 0);
            if (n > 0)
            {
                conn->RemoveOutbuffer(n);
                if (conn->OutbufferEmpty())
                    break;
            }
            else if (n == 0)
                break;
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                    break; // 跳出循环，向下执行
                else if (errno == EINTR)
                    continue;
                else
                {
                    conn->_excepter(conn);
                    return;
                }
            }

            // 如果发送缓冲区写满
            if (!conn->OutbufferEmpty())
            {
                conn->_R->EnableReadWrite(conn->Sockfd(), true, true); // 关心写事件
            }
            else
            {
                conn->_R->EnableReadWrite(conn->Sockfd(), true, false);
            }
        }
    }

    void HandlerExcept(Connection *conn)
    {
        errno = 0;
        LOG(DEBUG, "client %d quit\n", conn->Sockfd());
        conn->_R->RemoveConnetion(conn->Sockfd());
    }

private:
    func_t _func;
};